package reco.db.conf;

import org.apache.cayenne.conf.Configuration;

public final class RecoDomainLoader {

    private static Class<? extends RecoDomainLoadStrategy> loadStrategy;
    private static RecoDomainLoadStrategy loader;

    static {
        RecoDomainLoader.setLoadStrategy(DefaultRecoDomainLoadStrategy.class);
    }

    public RecoDomainLoader() {
        throw new UnsupportedOperationException("class is not instantiable");
    }

    /**
     * Inicializa la estrategia de carga con una clase definida por el usuario.
     * 
     * @param newLoadStrategy
     *            clase de la estrategia de carga de clases de dominio.
     * @throws NullPointerException
     *             si el argumento es null.
     * @throws IllegalArgumentException
     *             si la clase no puede ser instanciada mediante su constructor por defecto.
     */
    public synchronized static void setLoadStrategy(Class<?> newLoadStrategy) {
        if (newLoadStrategy == null) {
            throw new NullPointerException("newLoadStrategy");
        }

        if (!RecoDomainLoadStrategy.class.isAssignableFrom(newLoadStrategy)) {
            throw new IllegalArgumentException(newLoadStrategy.toString() + " is not an specialization of " + RecoDomainLoadStrategy.class);
        }
        // no deberia existir problema, se acaba de chequear que es del tipo esperado
        @SuppressWarnings("unchecked")
        final Class<? extends RecoDomainLoadStrategy> strategy = (Class<? extends RecoDomainLoadStrategy>) newLoadStrategy;

        if (loadStrategy != strategy) {
            setStrategy(strategy);
        }
    }

    private static void setStrategy(Class<? extends RecoDomainLoadStrategy> strategy) {
        loadStrategy = strategy;
        try {
            loader = loadStrategy.newInstance();
        } catch (final InstantiationException e) {
            throw new IllegalArgumentException(loadStrategy.toString() + " can not be instantiated", e);
        } catch (final IllegalAccessException e) {
            throw new IllegalArgumentException(loadStrategy.toString() + " can not be instantiated", e);
        }
    }

    public static void loadCayenneConfiguration(Configuration cayenneConfiguration) {
        loader.loadCayenneConfiguration(cayenneConfiguration);
    }
}
